﻿using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using NSwag.Annotations;
using ProxyServer.Yarp;
using Yarp.ReverseProxy;
using Yarp.ReverseProxy.Model;

namespace ProxyServer.Endpoints
{
    public static class BaseEndpoints
    {
        [OpenApiOperation(nameof(Publish), "Publish the current configuration", "")]
        public static Ok Publish([FromServices] AppProxyConfigProvider provider)
        {
            provider.Reload();
            return TypedResults.Ok();
        }

        [OpenApiOperation(nameof(GetCurrentRoutes), "", "")]
        public static List<RouteStateDto> GetCurrentRoutes([FromServices] IProxyStateLookup proxyState)
        {
            var routes = proxyState.GetRoutes()
                .Select(r => new RouteStateDto(
                    r.Config.RouteId,
                    r.Cluster?.ClusterId,
                    r.Cluster?.DestinationsState?.AllDestinations?.Count,
                    r.Cluster?.DestinationsState?.AvailableDestinations?.Count,
                    r.Cluster?.Destinations.ToDictionary(x => x.Key, y => new DestinationStateDto(y.Value.DestinationId, y.Value.Model.Config.Address, y.Value.ConcurrentRequestCount, y.Value.Health)))).ToList();

            return routes;
        }

        [OpenApiOperation(nameof(GetCurrentClusters), "", "")]
        public static List<ClusterStateDto> GetCurrentClusters([FromServices] IProxyStateLookup proxyState)
        {
            var clusters = proxyState.GetClusters()
                .Select(cl => new ClusterStateDto(
                    cl.ClusterId,
                    cl.DestinationsState.AllDestinations.Count,
                    cl.DestinationsState.AvailableDestinations.Count,
                    cl.Destinations.ToDictionary(x => x.Key, y => new DestinationStateDto(y.Value.DestinationId, y.Value.Model.Config.Address, y.Value.ConcurrentRequestCount, y.Value.Health)))).ToList();

            return clusters;
        }

        [OpenApiOperation(nameof(GetRoute), "", "")]
        public static void GetRoute([FromRoute] string id, [FromServices] IProxyStateLookup proxyState)
        {
            if (string.IsNullOrEmpty(id))
            {
                throw new ArgumentException("Route ID cannot be null or empty.", nameof(id));
            }
            proxyState.TryGetRoute(id, out var route);
        }

        [OpenApiOperation(nameof(GetCluster))]
        public static void GetCluster([FromRoute] string id, [FromServices] IProxyStateLookup proxyState)
        {

            if (string.IsNullOrEmpty(id))
            {
                throw new ArgumentException("Route ID cannot be null or empty.", nameof(id));
            }
            proxyState.TryGetCluster(id, out var cluster);
        }
    }

    public record DestinationStateDto(string DestinationId, string Address, int ConcurrentRequestCount, DestinationHealthState Health);
    public record ClusterStateDto(string ClusterId, int? AllDestinationsCount, int? AvailableDestinationsCount, IReadOnlyDictionary<string, DestinationStateDto> Destinations);
    public record RouteStateDto(string RouteId, string? ClusterId, int? AllDestinationsCount, int? AvailableDestinationsCount, IReadOnlyDictionary<string, DestinationStateDto>? Destinations);
}
